%{
#define _GNU_SOURCE
#define MAXDICO 1000
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdbool.h>
#include <search.h>
#include "y.tab.h"
#include "structure.h"

  FILE * fichier = NULL;
  /* CONTEXTE */
  enum Contexte contexte = GLOBALE;
  
  /* SYMBOL TABLE */
  Dico dico;
%}
   
%union{  /*définit le type de yyval : à indiquer dans les tokens*/
  /* Des types immuables... */
  char s[250];
  float f;
  int i;
  /* ... et une structure de transport plus portable */
  struct { 
    char s[250];
    float f;
    int i;
  } t;
 }

%token AND OR CLASS IF THEN ELSE END WHILE DO DEF LEQ GEQ 
%token STRING FOR TO RETURN IN NEQ
%token <s> ID
%token <i> INT
%token FLOAT

%left '*'
%left '/'
%left '+' '-'
%left '<' '>' LEQ GEQ EQ
%left AND OR

 /*%type topstmts topstmt stmts funcdefs funcdef opt_params params terms term opt_terms*/
%type <t> stmt
%type <t> lhs

%%

program		:  topstmts opt_terms
;

topstmts        :
| topstmt
| topstmts terms topstmt
{
  afficheDico(); /*DEBUG*/
}
;

topstmt	        : CLASS {contexte = DANSCLASSE;} classcorpus END {contexte = GLOBALE;}
| funcdef
| stmt
;

classcorpus          :   ID term funcdefs terms
| '<' ID term funcdefs
;

stmts	        : /* none */
| stmt
| stmts terms stmt
;

stmt		:  IF expr THEN stmts terms optelse END
{;}
| FOR ID IN expr TO expr DO term stmts terms END
{;}
| WHILE expr DO term stmts terms END 
{;}
| lhs '=' expr
{
  /*Ajout d'une variable*/
  strcpy(dico.tab[dico.sommet].id, $1.s);
  switch(contexte){
  case GLOBALE:
    dico.tab[dico.sommet].classe = GLOB;
    break;
  case ARGUMENT:
    dico.tab[dico.sommet].classe = ARG;
    break;
  case LOCALE:
    dico.tab[dico.sommet].classe = LOC;
    break;
  case DANSCLASSE:
    if(dico.tab[dico.sommet].id[0] == '@')
      dico.tab[dico.sommet].classe = CLASSEATTR;
    else
      dico.tab[dico.sommet].classe = LOC;
    break;
  }
  dico.tab[dico.sommet].type[0] = (enum Type) ENTIER;
  dico.tab[dico.sommet].adresse = 0;
  dico.sommet++;
}
| lhs
{;}
| RETURN expr
{;}
;

optelse          : /* none */
| ELSE stmts terms
;

funcdefs        : /* none */
| funcdef
| funcdefs terms funcdef
;

/*mettre à part la définition de fonction*/
funcdef         : DEF 
{
  switch(contexte){
  case DANSCLASSE:
    break;
  case GLOBALE:
    contexte = LOCALE;
    break;
  default:
    exit(EXIT_SUCCESS);
  }
} ID opt_params terms stmts terms END 
{
  /*Maj contexte*/
  switch(contexte){
  case DANSCLASSE:
    break;
  case LOCALE:
    contexte = GLOBALE;
    break;
  default:
    exit(EXIT_SUCCESS);
  }
  /*Suppression de la table locale du dico*/
  while(dico.tab[dico.sommet].classe == LOC || dico.tab[dico.sommet].classe == ARG){
    dico.sommet--;
  }
}
;

opt_params      : /* none */
| '(' ')'
| '(' params ')'
;

params          : ID ',' params
| ID
;

lhs             : ID
{strcpy($$.s,$1);}
| ID '.' lhs
{;}
| ID '(' exprs ')'
{;}
| ID '(' exprs ')' '.' lhs
{;}
;

exprs           : exprs ',' expr
| expr
;

primary         : lhs
| STRING
| FLOAT
| INT
| '(' expr ')'
;

expr            : expr AND comp_expr
| expr OR comp_expr
| comp_expr
| ID '.' ID opt_params
;

comp_expr       : additive_expr '<' additive_expr
| additive_expr '>' additive_expr
| additive_expr LEQ additive_expr
| additive_expr GEQ additive_expr
| additive_expr EQ additive_expr
| additive_expr NEQ additive_expr
| additive_expr
;

additive_expr   : multiplicative_expr
| additive_expr '+' multiplicative_expr
| additive_expr '-' multiplicative_expr
;

multiplicative_expr : multiplicative_expr '*' primary 
| multiplicative_expr '/' primary
| primary
;

opt_terms	: /* none */
| terms
;

terms		: terms ';'
| terms '\n'
| ';'
| '\n'
;

term            : ';'
| '\n'
;

%%

int main() {
  // initialisation du dictionnaire :
  dico.base = 0;
  dico.sommet = 0;

  // /*Ajout d'une variable*/
  // dico.sommet++;
  // strcpy(dico.tab[dico.sommet].id, "u");
  // dico.tab[dico.sommet].classe = GLOB;
  // dico.tab[dico.sommet].type[0] = (enum Type) ENTIER;
  // dico.tab[dico.sommet].adresse = 0;

  afficheDico();

  // ouverture du fichier utilisé pour la sortie en llvm
  fichier = fopen("retour.c", "w+");

  // parse
  yyparse(); 

  fclose(fichier);
  return 0;
}
